/*******************************************************
 *                                                     *
 *  draw.file Library        GCW  25/12/94             *
 *                                                     *
 *******************************************************/

/* Uses draw.object */

#ifndef _draw_object
#include bob:draw.object
#endif

#ifndef _draw_file
#define _draw_file 1
#endif

class drawfile
{
  obj, bbx_lo, bby_lo, bbx_hi, bby_hi;
}

drawfile::drawfile()
{
 obj = new object(16<<10);
 bbx_lo = bby_lo = &7fffffff;
 bbx_hi = bby_hi = &80000000;
 return this;
}

drawfile::adjust_box(x_lo,y_lo,x_hi,y_hi)
{
 bbx_lo = min(bbx_lo,x_lo);
 bby_lo = min(bby_lo,y_lo);
 bbx_hi = max(bbx_hi,x_hi);
 bby_hi = max(bby_hi,y_hi);
}

min(a,b)
{ return (a<b)?a:b; }

max(a,b)
{ return (a<b)?b:a; }

drawfile::file_header()
{
 obj->push_word(&77617244);
 obj->push_word(201);
 obj->push_word(0);
 obj->push_string(pad("Armbob",12,' '));
 obj->push_word(0);        // bounding box x_lo
 obj->push_word(0);        // bounding box y_lo
 obj->push_word(0);        // bounding box x_hi
 obj->push_word(0);        // bounding box y_hi
}

drawfile::object_header(type,size)
{
 local adr;
 adr = obj->here();
 obj->push_word(type);
 obj->push_word(size);
 obj->push_word(0);        // bounding box x_lo
 obj->push_word(0);        // bounding box y_lo
 obj->push_word(0);        // bounding box x_hi
 obj->push_word(0);        // bounding box y_hi
 return adr;
}

set_box(a,x_lo,y_lo,x_hi,y_hi)
{
 in (a+8) put { x_lo; y_lo; x_hi; y_hi; }
}

drawfile::options()
{
 local adr, i;
 adr = this->object_header(11,88);

 obj->push_word(&500);    // A4 paper
 for (i = 0; i <15; i++)
      obj->push_word(0);  // words zero except those set below
               // no paper limits,portrait,no printer limits
 putword(adr+32,&3ff00000);    // grid spacing=1
 putword(adr+40,2);            // grid division
               // grid: rectangular,auto off,not shown,lock off,inches
 putword(adr+64,1);            // zoom multiplier
 putword(adr+68,1);            // zoom divider
               // zoom lock off,no toolbox
 putword(adr+80,128);          // select mode
 putword(adr+84,5000);         // undo buffer (bytes)

 return adr;
}

drawfile::fonts()
{
 local adr;
 obj->push_word(0);
 adr = obj->here();
 obj->push_word(0);     // size
 obj->push_byte(1);
 obj->push_string("Trinity.Medium"+0);
 obj->push_byte(2);
 obj->push_string("Trinity.Medium.Italic"+0);
 obj->push_byte(3);
 obj->push_string("Trinity.Bold"+0);
 obj->push_byte(4);
 obj->push_string("Trinity.Bold.Italic"+0);
 obj->push_byte(5);
 obj->push_string("Corpus.Medium"+0);
 obj->push_byte(6);
 obj->push_string("Corpus.Medium.Oblique"+0);
 obj->push_byte(7); 
 obj->push_string("Corpus.Bold"+0);
 obj->push_byte(8);
 obj->push_string("Corpus.Bold.Oblique"+0);
 obj->push_byte(9);
 obj->push_string("Homerton.Medium"+0);
 obj->push_byte(10);
 obj->push_string("Homerton.Medium.Oblique"+0);
 obj->push_byte(11);
 obj->push_string("Homerton.Bold"+0);
 obj->push_byte(12);
 obj->push_string("Homerton.Bold.Oblique"+0);
 while(obj->here()%4)
    obj->push_byte(0);
 putword(adr,4+(obj->here()) - adr);
}

/* <<<<<<<<<<<<<<< text >>>>>>>>>>>>>>> */
drawfile::text(s,x,y)
{
 local len,adr,x1,y1;
 x *= 640; y *= 640;   // 1 point units
 len = sizeof(s);
 s = zero_align(s);
 adr = this->object_header(1, 52+sizeof(s));
 obj->push_word(colour_trans(7));   // text colour
 obj->push_word(colour_trans(0));   // background colour
 obj->push_word(0);                 // system font
 obj->push_word(6400);              // 10 point fontsize_x
 obj->push_word(6400);              // 10 point fontsize_y
 obj->push_word(x);
 obj->push_word(y);
 obj->push_string(s);
 set_box(adr,x,y,(x1 = x+len*word(adr+36)),(y1 = y+word(adr+40)));
 this->adjust_box(x,y,x1,y1);
 return adr;
}

colour(adr,n)
{ putword(adr+24,colour_trans(n)); }

font(adr,n)
{ putword(adr+32,n); }

drawfile::font_x(adr,n)        // n in points
{
 local len, x, y, x1, y1;
 putword(adr+36,640*n);
 len = word(adr+4)-52;
 set_box(adr, (x = word(adr+44)), (y = word(adr+48)),
      (x1 = x + len*word(adr+36)),(y1 = y + word(adr+40)));
 this->adjust_box(x,y,x1,y1);
}

drawfile::font_y(adr,n)
{
 local len, x, y, x1, y1;
 putword(adr+40, 640*n);
 len = word(adr+4)-52;
 set_box(adr, (x = word(adr+44)), (y = word(adr+48)),
   (x1 = x + len*word(adr+36)),(y1 = y + word(adr+40)));
 this->adjust_box(x,y,x1,y1);
}

/* <<<<<<<<<<<<<< path >>>>>>>>>>>>>> */
drawfile::path()
{
 local adr;
 adr = this->object_header(2,0);
 obj->push_word(-1);              // fill colour
 obj->push_word(colour_trans(7)); // outline colour
 obj->push_word(640);             // width
 obj->push_word(0);               // style
 return adr;
}
 
fill(adr,n)
{ putword(adr+24,colour_trans(n)); }

outline(adr,n)
{ putword(adr+28,colour_trans(n)); }

linewidth(adr,n)
{ putword(adr+32,640*n); }

join_style(adr,n)
{ putword(adr+36,(&fffffffc & word(adr+36))|(n%3)); }

endcap_style(adr,n)
{ putword(adr+36,((~12)& word(adr+36))|((n%3)<<2)); }

startcap_style(adr,n)
{ putword(adr+36,((~48)& word(adr+36))|((n%3)<<4)); }

winding_rule(adr,n)
{ putword(adr+36,((~64)& word(adr+36))|((n%2)<<6)); }

drawfile::endpath(adr)
{
 obj->push_word(0);
 putword(adr+4,(obj->here())-adr);
 putword(adr+8,bbx_lo);
 putword(adr+12,bby_lo);
 putword(adr+16,bbx_hi);
 putword(adr+20,bby_hi);
}

drawfile::close_with_line()
{ obj->push_word(5); }

drawfile::move(x,y)
{ 
 x *= 640;
 y *= 640;
 obj->push_word(2);
 obj->push_word(x);
 obj->push_word(y);
 this->adjust_box(x,y,x,y);
} 

drawfile::draw(x,y)
{ 
 x *= 640;
 y *= 640; 
 obj->push_word(8);
 obj->push_word(x);
 obj->push_word(y);
 this->adjust_box(x,y,x,y);
}

drawfile::bezier(x1,y1,x2,y2,x3,y3)
{ 
 x1 *= 640;
 y1 *= 640;
 x2 *= 640;
 y2 *= 640;
 x3 *= 640;
 y3 *= 640;
 obj->push_word(6);
 obj->push_word(x1);
 obj->push_word(y1);
 obj->push_word(x2);
 obj->push_word(y2);
 obj->push_word(x3);
 obj->push_word(y3);
 this->adjust_box(x1,y1,x1,y1);
 this->adjust_box(x2,y2,x2,y2);
 this->adjust_box(x3,y3,x3,y3);
} 

/* <<<<<<<<<<<<<<<< group >>>>>>>>>>>>>>> */
drawfile::group()
{
 local adr;
 adr = this->object_header(6,0);
 obj->push_word(&20202020);
 obj->push_word(&20202020);
 obj->push_word(&20202020);
 return adr;
}

drawfile::endgroup(adr)
{
 putword(adr+4,(obj->here())-adr);
 putword(adr+8,bbx_lo);
 putword(adr+12,bby_lo);
 putword(adr+16,bbx_hi);
 putword(adr+20,bby_hi);
}

/* <<<<<<<<<<<<<<<<< begin >>>>>>>>>>>>>>> */
drawfile::begin()
{
 init_names();
 this->file_header();
 this->fonts(); 
 this->options();
}

/* <<<<<<<<<<<<<<<<< show >>>>>>>>>>>>>>>> */ 
drawfile::end(filename)
{
 obj->write(24,bbx_lo);
 obj->write(28,bby_lo);
 obj->write(32,bbx_hi);
 obj->write(36,bby_hi);
 save(obj->start(), obj->here(), filename, &aff);
 oscli("set Draw$Options P4 T- MS");
 oscli("filer_run "+filename);
}

save(from,to,file,type)
{
 local r;
 r = newvector(8);
 r[0] = 10;
 r[1] = @(file);
 r[2] = type;
 r[4] = from;
 r[5] = to;
 swi(8|(1<<17),r);
} 

align(n)
{ return (n%4)?((1+(n>>2))<<2):n; }

/* pad string s out to n characters with character c */
pad(s,n,c)
{
 local t, i;
 if (sizeof(s) >= n)
  for ( t = "", i = 0; i < n; t += s[i++]);
 else
  for ( t = s; sizeof(t) < n; t += c);
 return t;
}

zero_align(s)
{
 local t;
 t = s+0;
 while (sizeof(t)%4)
    t += 0;
 return t;
}

colour_trans(n)
{
 local r;
 if (n == -1) return n;
 (r = newvector(8))[1] = @(newstring(80));
 r[2] = &45555254;
 swi("Wimp_ReadPalette",r);
 return (&ffffff00)&word(r[1]+4*n);
}

init_names()
{
 none = -1;
 white = 0;
 black = 7;
 blue = 8;
 yellow = 9;
 green = 10;
 red = 11;
 cream = 12;
 olive = 13;
 orange = 14;
 azure = 15;
 System = 0;
 Trinity_Medium = 1;
 Trinity_Medium_Italic = 2;
 Trinity_Bold = 3;
 Trinity_Bold_Italic = 4;
 Corpus_Medium = 5;
 Corpus_Medium_Oblique = 6;
 Corpus_Bold = 7;
 Corpus_Bold_Oblique = 8;
 Homerton_Medium = 9;
 Homerton_Medium_Oblique = 10;
 Homerton_Bold = 11;
 Homerton_Bold_Oblique = 12;
 Mitred = 0;
 Round = 1;
 Bevelled = 2;
 Butt = 0;
 Square = 2;
 Non_Zero = 0;
 Even_Odd = 1;
}

/* ------------ end of file definitions --------- */